{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Examples of usage of Gate Angle Placeholder\n",
    "\n",
    "The word \"Placeholder\" is used in Qubiter (we are in good company, Tensorflow uses this word in the same way) to mean a variable for which we delay/postpone assigning a numerical value (evaluating it) until a later time. In the case of Qubiter, it is useful to define gates with placeholders standing for angles. One can postpone evaluating those placeholders until one is ready to call the circuit simulator, and then pass the values of the placeholders as an argument to the simulator’s constructor. Placeholders of this type can be useful, for example, with quantum neural nets (QNNs). In some QNN algorithms, the circuit gate structure is fixed but the angles of the gates are varied many times, gradually, trying to lower a cost function each time.\n",
    "\n",
    "> In Qubiter, legal variable names must be of form `#3` or `-#3` or `#3*.5` or\n",
    "`-#3*.5` where 3 can be replaced by any non-negative int, and .5 can\n",
    "be replaced by anything that can be an argument of float() without\n",
    "throwing an exception. In this example, the 3 that follows the hash\n",
    "character is called the variable number\n",
    "\n",
    ">NEW! (functional placeholder variables)\n",
    "Now legal variable names can ALSO be of the form `my_fun#1#2` or\n",
    "`-my_fun#1#2`, where\n",
    "* the 1 and 2 can be replaced by any non-negative integers and there\n",
    "might be any number > 0 of hash variables. Thus, there need not\n",
    "always be precisely 2 hash variables as in the example.\n",
    "* `my_fun` can be replaced by the name of any function with one or\n",
    "more input floats (2 inputs in the example), as long as the first\n",
    "character of the function's name is a lower case letter.\n",
    "\n",
    ">The strings `my_fun#1#2` or `-my_fun#1#2` indicate than one wants to\n",
    "use for the angle being replaced, the values of `my_fun(#1, #2)` or\n",
    "`-my_fun(#1, #2)`, respectively, where the inputs #1 and #2 are\n",
    "floats standing for radians and the output is also a float standing\n",
    "for radians.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks\n",
      "/home/rrtucci/PycharmProjects/qubiter\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import sys\n",
    "print(os.getcwd())\n",
    "os.chdir('../../')\n",
    "print(os.getcwd())\n",
    "sys.path.insert(0,os.getcwd())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We begin by writing a simple circuit with 4 qubits. As usual, the following code will\n",
    "write an English and a Picture file in the `io_folder` directory. Note that some\n",
    "angles have been entered into the write() Python functions as legal\n",
    "variable names instead of floats. In the English file, you will see those legal\n",
    "names where the numerical values of those angles would have been."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loaded OneQubitGate, WITHOUT autograd.numpy\n"
     ]
    }
   ],
   "source": [
    "from qubiter.SEO_writer import *\n",
    "from qubiter.SEO_reader import *\n",
    "from qubiter.EchoingSEO_reader import *\n",
    "from qubiter.SEO_simulator import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_qbits = 4\n",
    "file_prefix = 'placeholder_test'\n",
    "emb = CktEmbedder(num_qbits, num_qbits)\n",
    "wr = SEO_writer(file_prefix, emb)\n",
    "wr.write_Rx(2, rads=np.pi/7)\n",
    "wr.write_Rx(1, rads='#2*.5')\n",
    "wr.write_Rx(1, rads='my_fun1#2')\n",
    "wr.write_Rn(3, rads_list=['#1', '-#1*3', '#3'])\n",
    "wr.write_Rx(1, rads='-my_fun2#2#1')\n",
    "wr.write_cnot(2, 3)\n",
    "wr.close_files()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following 2 files were just written:\n",
    "1. <a href='../io_folder/placeholder_test_4_eng.txt'>../io_folder/placeholder_test_4_eng.txt</a>\n",
    "2. <a href='../io_folder/placeholder_test_4_ZLpic.txt'>../io_folder/placeholder_test_4_ZLpic.txt</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Simply by creating an object of the class SEO_reader with the flag `write_log` set equal to True, you can create a log file which contains \n",
    "\n",
    "* a list of distinct variable numbers \n",
    "* a list of distinct function names\n",
    "\n",
    "encountered in the English file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "rdr = SEO_reader(file_prefix, num_qbits, write_log=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following log file was just written:\n",
    "    \n",
    "<a href='../io_folder/placeholder_test_4_log.txt'>../io_folder/placeholder_test_4_log.txt</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let us create two functions that will be used for the functional placeholders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_fun1(x):\n",
    "    return x*.5\n",
    "\n",
    "def my_fun2(x, y):\n",
    "    return x + y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Partial Substitution**\n",
    "\n",
    "This creates new files\n",
    "\n",
    "with `#1=30`, `#2=60`, `'my_fun1'->my_fun1`,\n",
    "\n",
    "but `#3`  and `'my_fun2'` still undecided"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<qubiter.EchoingSEO_reader.EchoingSEO_reader at 0x7f08b0036d50>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vman = PlaceholderManager(eval_all_vars=False,\n",
    "            var_num_to_rads={1: np.pi/6, 2: np.pi/3},\n",
    "            fun_name_to_fun={'my_fun1': my_fun1})\n",
    "wr = SEO_writer(file_prefix + '_eval01', emb)\n",
    "EchoingSEO_reader(file_prefix, num_qbits, wr,\n",
    "                  vars_manager=vman)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following 2 files were just written:\n",
    "1. <a href='../io_folder/placeholder_test_eval01_4_eng.txt'>../io_folder/placeholder_test_eval01_4_eng.txt</a>\n",
    "2. <a href='../io_folder/placeholder_test_eval01_4_ZLpic.txt'>../io_folder/placeholder_test_eval01_4_ZLpic.txt</a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following code runs the simulator after substituting\n",
    "\n",
    "`#1=30`, `#2=60`, `#3=90`, `'my_fun1'->my_fun1`, `'my_fun2'->my_fun2`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "*********branch= pure\n",
      "total probability of state vector (=one if no measurements)= 1.000000\n",
      "dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
      "{0: (1.0, -0.0),\n",
      " 1: (0.75, 0.25),\n",
      " 2: (0.811745, 0.188255),\n",
      " 3: (0.623513, 0.376487)}\n"
     ]
    }
   ],
   "source": [
    "vman = PlaceholderManager(\n",
    "    var_num_to_rads={1: np.pi/6, 2: np.pi/3, 3: np.pi/2},\n",
    "    fun_name_to_fun={'my_fun1': my_fun1, 'my_fun2': my_fun2}\n",
    ")\n",
    "sim = SEO_simulator(file_prefix, num_qbits, verbose=False,\n",
    "                    vars_manager=vman)\n",
    "StateVec.describe_st_vec_dict(sim.cur_st_vec_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
